package puzzle.game;

import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.prefs.Preferences;
import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.Music;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.Sound;
import org.newdawn.slick.gui.AbstractComponent;
import org.newdawn.slick.gui.BasicComponent;
import org.newdawn.slick.gui.ComponentListener;
import org.newdawn.slick.state.GameState;
import org.newdawn.slick.state.StateBasedGame;
import org.newdawn.slick.state.transition.Transition;
import org.newdawn.slick.util.Log;
import puzzle.game.BallPuzzle;
import puzzle.game.states.ExitState;
import puzzle.game.states.HelpState;
import puzzle.game.states.LoadingState;
import puzzle.game.states.MenuState;
import puzzle.game.states.PuzzleState;
import puzzle.game.states.StandardIngameState;
import puzzle.game.states.UserIngameState;
import puzzle.game.ui.PuzzleButton;
import puzzle.util.ResourceManager;

public class BallPuzzle extends StateBasedGame {
  
  /** Entry point to the application game. */
  public static void main(String[] args) {
    boolean debug = (args.length>=1 && args[0].equals("-d"));
    Log.setVerbose(debug);
    
    //whether we should print to file
    if (debug) {
      try { Log.out = new PrintStream("debug.txt"); }
      catch (FileNotFoundException e) {}
    }
    
    try {
      //Slick2D has a great implementation for both Applets
      //and Applications. I use an AppGameContainer because
      //this is the entry point for an application.
      
      //An applet would use the AppletGameContainer.
      BallPuzzle g = new BallPuzzle();
      AppGameContainer container = new AppGameContainer(g);
      container.setDisplayMode(640, 480, false); //not fullscreen
      try {
      container.start();
      } catch (SlickException e)
  		{
  			// TODO Auto-generated catch block
  			e.printStackTrace();
  		}
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
  
  private LoadingState loading;
  private UserIngameState user_ingame;
  private StandardIngameState std_ingame;
  private MenuState menu;
  private ExitState exit;
  private HelpState help;
  private Music music;
  
  private Color upCol = new Color(163, 209, 242);
  private Color downCol = new Color(193, 228, 248);
  private Color rollCol = Color.white;
  private PuzzleButton soundButton = null;
  
  private String soundOn = ResourceManager.getString("audio.on", "Sound On");
  private String soundOff = ResourceManager.getString("audio.off", "Sound Off");
  
  private boolean showFPS = true;
  
  private static Preferences prefs = null;
  static {
    try {
        prefs = Preferences.userNodeForPackage(BallPuzzle.class);
    } catch (SecurityException e) {
        Log.warn("Can't use Preferences with current security.");
    }
  }
  
  public BallPuzzle() {
    super("cyber2d");
    
    /*try {
        Runtime.getRuntime().addShutdownHook(new Thread() {
          { 
            setName("BPuz cleanup");
            setDaemon(false);
          }
          
          public void run() {
            if (prefs!=null) {
                prefs.putInt("game.std.map", std_ingame.getMapIndex());
                prefs.putInt("game.user.map", user_ingame.getMapIndex());
                prefs.putBoolean("game.soundOn", getContainer().isSoundOn()||getContainer().isMusicOn());
            }
            //if we are debugging
            if (Log.out != System.out) {
              Log.out.close();
            }
          }
        });
    } catch (IllegalStateException e) {
        Log.warn("Early shutdown.");
    } catch (SecurityException e) {
        Log.warn("Can't register shutdown hook with current security.");
    }*/
  }
  
  public void initStatesList(GameContainer container) throws SlickException {
    container.setShowFPS(showFPS);
    
    boolean b = (prefs!=null) ? prefs.getBoolean("game.soundOn", true) : true;
    
    //TODO: use preferences & music
            
    container.setSoundOn(b);
    container.setMusicOn(b);
    
    String str = (container.isSoundOn()||container.isMusicOn()) ? soundOff : soundOn;
    soundButton = new PuzzleButton(container, str) {
        public void renderImpl(GameContainer c, Graphics g) {
            String str = (c.isSoundOn()||c.isMusicOn()) ? soundOff : soundOn;
            setText(str);
            super.renderImpl(c, g);
        }
    };
    soundButton.setLocation(container.getWidth()-soundButton.getWidth()-10, 5);
    soundButton.setColor(PuzzleButton.ROLLOVER, rollCol);
    soundButton.setColor(PuzzleButton.UP, upCol);
    soundButton.setColor(PuzzleButton.DOWN, downCol);
    soundButton.addComponentListener(new ComponentListener() {
        public void componentActivated(BasicComponent c) {
            boolean on = !(getContainer().isMusicOn() || getContainer().isSoundOn());
                       
            getContainer().setMusicOn(on);
            getContainer().setSoundOn(on);
            
            //turning off music
            if (!on) {
                LoadingState l = getLoadingState();
                if (l!=null) {
                    Sound port = l.getPortSound();
                    Sound trans = l.getTransitionSound();
                    if (port!=null&&port.playing())
                        port.stop();
                    if (trans!=null&&trans.playing())
                        trans.stop();
                }
            }
            //turning on music
            else {
                int id = getCurrentStateID();
                if (id!=UserIngameState.ID 
                        && id!=StandardIngameState.ID) {
                    if (getMusic()!=null) {
                      getMusic().stop();
                    }
                }
                if (id==MenuState.ID) {
                    if (getMenuState()!=null) {
                        getMenuState().playTransitionSound();
                    }
                }
            }
        }

		public void componentActivated(AbstractComponent arg0)
		{
			// TODO Auto-generated method stub
			
		}
    });
    
    //the icons for the window & alt+tab
    String[] s = {
      ResourceManager.getString("icon.window", "data/icon.png"),
      ResourceManager.getString("icon.alt_tab", "data/icon2.png")
    };
    container.setIcons(s);
    
    //add loading state and enter it
    loading = new LoadingState(this);
    addState(loading);
    loading.setStarted(true);
    
    //add menu state
    menu = new MenuState(this);
    addState(menu);
    
    //add help state
    help = new HelpState(this);
    addState(help);    
    
    //gets last game map
    int i = (prefs!=null) ? prefs.getInt("game.std.map", 0) : 0;
        
    //add regular ingame state
    std_ingame = new StandardIngameState(this);
    std_ingame.setMapIndex(i);
    addState(std_ingame);
    
    //gets last user map
    i = (prefs!=null) ? prefs.getInt("game.user.map", 0) : 0;
    
    //add user ingame state
    user_ingame = new UserIngameState(this);
    addState(user_ingame);
    
    //exit state
    exit = new ExitState(this);
    addState(exit);
  }
  
  public MenuState getMenuState() {
    return menu;
  }
  
  public PuzzleButton getSoundSwitch() {
    return soundButton;
  }
  
  public UserIngameState getUserIngameState() {
    return user_ingame;
  }
  
  public LoadingState getLoadingState() {
    return loading;
  }
  
  public StandardIngameState getStandardIngameState() {
    return std_ingame;
  }
  
  public ExitState getExitState() {
    return exit;
  }
  
  public HelpState getHelpState() {
    return help;
  }
  
  public Music getMusic() {
    return music;
  }
  
  public void setMusic(Music m) {
    this.music = m;
  }
  
  public void globalKeyPressed(int key, char c) {
    if (key == Input.KEY_F) {
      showFPS = !showFPS;
      getContainer().setShowFPS(showFPS);
    }
  }
  
  public void enterState(int id, Transition t1, Transition t2) {
    GameState t = getState(id);
    if (t instanceof PuzzleState) {
      PuzzleState s = ((PuzzleState)t);
      if (!s.isStarted()) {
        s.setStarted(true);
        try {
          s.startState(getContainer());
        }
        catch (SlickException e) {
          Log.error(e);
        }
      }
    }
    super.enterState(id, t1, t2);
  }
}
